/*
 *  Arrow
 *
 *  Created by David Giovannini on 1/5/07.
 *  Copyright 2007 Software by Jove. All rights reserved.
 *
 */
 
namespace SBJ
{

namespace Arrow
{

namespace
{
class MessageInfo
{
public:
	MessageInfo( const Message& msg )
	: m_info( "Message <" + msg.getTopic().getPublicationKey() + ":" + msg.getTopic().getTopicKey() )
	{
	}
	operator const std::string& ( void ) const
	{
		return m_info;
	}
	std::string m_info;
};
}

template < typename MsgType, typename Allocator >
TMsgProxy< MsgType, Allocator >::TMsgProxy( const IExceptionObserver::Ptr& excObserver, const Allocator& alloc )
: m_alloc( alloc )
, m_excObserver( excObserver )
{
}

template < typename MsgType, typename Allocator >
TMsgProxy< MsgType, Allocator >::~TMsgProxy( void )
{
}

template < typename MsgType, typename Allocator > size_t
TMsgProxy< MsgType, Allocator >::getMsgSize( void ) const
{
	return sizeof( MsgType );
}

template < typename MsgType, typename Allocator > bool
TMsgProxy< MsgType, Allocator >::fullyIndependent( void ) const
{
	return MsgType::fully_independent;
}
	
template < typename MsgType, typename Allocator > Message*
TMsgProxy< MsgType, Allocator >::duplicate( Message& msg ) const
{
	try
	{
		MsgType* newMsg = m_alloc.allocate( 1 );
		m_alloc.construct( newMsg, static_cast< MsgType& >( msg ) );
		return newMsg;
	}
	catch ( std::exception& exception )
	{
		if ( m_excObserver ) m_excObserver->onException( exception, MessageInfo( msg ) );
	}
	catch ( ... )
	{
		if ( m_excObserver ) m_excObserver->onException( std::logic_error( "Unknown duplicate error" ), MessageInfo( msg ) );		
	}
	return 0;
}

template < typename MsgType, typename Allocator > Message*
TMsgProxy< MsgType, Allocator >::replace( Message* oldMsg, Message& newMsg ) const
{
	try
	{
		m_alloc.destroy( static_cast< MsgType* >( oldMsg ) );
		m_alloc.construct( static_cast< MsgType* >( oldMsg ), static_cast< MsgType& >( newMsg ) );
		return oldMsg;
	}
	catch ( std::exception& exception )
	{
		if ( m_excObserver ) m_excObserver->onException( exception, MessageInfo( *oldMsg ) );
	}
	catch ( ... )
	{
		if ( m_excObserver ) m_excObserver->onException( std::logic_error( "Unknown replace error" ), MessageInfo( *oldMsg ) );		
	}
	return 0;
}

template < typename MsgType, typename Allocator > void
TMsgProxy< MsgType, Allocator >::free( Message* oldMsg ) const
{
	try
	{
		m_alloc.destroy( static_cast< MsgType* >( oldMsg ) );
		m_alloc.deallocate( static_cast< MsgType* >( oldMsg ), 1 );
	}
	catch ( std::exception& exception )
	{
		if ( m_excObserver ) m_excObserver->onException( exception, MessageInfo( *oldMsg ) );
	}
	catch ( ... )
	{
		if ( m_excObserver ) m_excObserver->onException( std::logic_error( "Unknown delete error" ), MessageInfo( *oldMsg ) );		
	}	
}


inline boost::tribool
MsgProxy::isValid( const Message& msg )
{
	if ( msg.getTopic().isValid() == false )
		return false;
	return msg.getTopic().getMsgProxy().isValidSelf( msg );
}

template < typename MsgType, typename Allocator > boost::tribool
TMsgProxy< MsgType, Allocator >::isValidSelf( const Message& msg ) const
{
	try
	{
		return static_cast< const MsgType& >( msg ).isValid();
	}
	catch ( std::exception& exception )
	{
		if ( m_excObserver ) m_excObserver->onException( exception, MessageInfo( msg ) );
	}
	catch ( ... )
	{
		if ( m_excObserver ) m_excObserver->onException( std::logic_error( "Unknown isValid error" ), MessageInfo( msg ) );		
	}
	return boost::indeterminate;
}

template < typename MsgType, typename Allocator > boost::tribool
TMsgProxy< MsgType, Allocator >::doesConsume( const Message& msg, const Message& rhs ) const
{
	try
	{
		return static_cast< const MsgType& >( msg ).doesConsume( static_cast< const MsgType& >( rhs ) );
	}
	catch ( std::exception& exception )
	{
		if ( m_excObserver ) m_excObserver->onException( exception, MessageInfo( msg ) );
	}
	catch ( ... )
	{
		if ( m_excObserver ) m_excObserver->onException( std::logic_error( "Unknown doesConsume error" ), MessageInfo( msg ) );		
	}
	return boost::indeterminate;
}

template < typename MsgType, typename Allocator > void
TMsgProxy< MsgType, Allocator >::consume( Message& msg, Message& rhs ) const
{
	try
	{
		static_cast< MsgType& >( msg ).consume( static_cast< MsgType& >( rhs ) );
	}
	catch ( std::exception& exception )
	{
		if ( m_excObserver ) m_excObserver->onException( exception, MessageInfo( msg ) );
	}
	catch ( ... )
	{
		if ( m_excObserver ) m_excObserver->onException( std::logic_error( "Unknown consume error" ), MessageInfo( msg ) );		
	}
}

template < typename MsgType, typename Allocator > size_t
TMsgProxy< MsgType, Allocator >::getThreadedThreshold( Message& msg ) const
{
	try
	{
		return msg.getThreadedThreshold();
	}
	catch ( std::exception& exception )
	{
		if ( m_excObserver ) m_excObserver->onException( exception, MessageInfo( msg ) );
	}
	catch ( ... )
	{
		if ( m_excObserver ) m_excObserver->onException( std::logic_error( "Unknown getThreadedThreshold error" ), MessageInfo( msg ) );		
	}
	return -1;
}
	
template < typename MsgType, typename Allocator > boost::tribool
TMsgProxy< MsgType, Allocator >::doesBlockOnDispatch( Message& msg ) const
{
	try
	{
		return msg.doesBlockOnDispatch();
	}
	catch ( std::exception& exception )
	{
		if ( m_excObserver ) m_excObserver->onException( exception, MessageInfo( msg ) );
	}
	catch ( ... )
	{
		if ( m_excObserver ) m_excObserver->onException( std::logic_error( "Unknown doesBlockOnDispatch error" ), MessageInfo( msg ) );		
	}
	return boost::indeterminate;
}
	
template < typename MsgType, typename Allocator > boost::tribool
TMsgProxy< MsgType, Allocator >::beginInvocations( Message& msg, size_t count ) const
{
	try
	{
		return msg.beginInvocations( count );
	}
	catch ( std::exception& exception )
	{
		if ( m_excObserver ) m_excObserver->onException( exception, MessageInfo( msg ) );
	}
	catch ( ... )
	{
		if ( m_excObserver ) m_excObserver->onException( std::logic_error( "Unknown beginInvocations error" ), MessageInfo( msg ) );		
	}
	return boost::indeterminate;
}

template < typename MsgType, typename Allocator > void
TMsgProxy< MsgType, Allocator >::invoke( Message& msg, void* subscriber ) const
{
	try
	{
		static_cast< MsgType& >( msg ).invoke( reinterpret_cast< typename MsgType::Subscriber* >( subscriber ) );
	}
	catch ( std::exception& exception )
	{
		if ( m_excObserver ) m_excObserver->onException( exception, MessageInfo( msg ) );
	}
	catch ( ... )
	{
		if ( m_excObserver ) m_excObserver->onException( std::logic_error( "Unknown invocation error" ), MessageInfo( msg ) );		
	}
}

template < typename MsgType, typename Allocator > void
TMsgProxy< MsgType, Allocator >::endInvocations( Message& msg ) const
{
	try
	{
		msg.endInvocations();
	}
	catch ( std::exception& exception )
	{
		if ( m_excObserver ) m_excObserver->onException( exception, MessageInfo( msg ) );
	}
	catch ( ... )
	{
		if ( m_excObserver ) m_excObserver->onException( std::logic_error( "Unknown endInvocations error" ), MessageInfo( msg ) );		
	}
}

template < typename MsgType, typename Allocator > void
TMsgProxy< MsgType, Allocator >::execute( Message& msg ) const
{
	try
	{
		msg.execute();
	}
	catch ( std::exception& exception )
	{
		if ( m_excObserver ) m_excObserver->onException( exception, MessageInfo( msg ) );
	}
	catch ( ... )
	{
		if ( m_excObserver ) m_excObserver->onException( std::logic_error( "Unknown execute error" ), MessageInfo( msg ) );		
	}
}

template < typename MsgType, typename Allocator > void
TMsgProxy< MsgType, Allocator >::dropped( Message& msg, Message::EDropped reason ) const
{
	try
	{
		msg.dropped( reason );
	}
	catch ( std::exception& exception )
	{
		if ( m_excObserver ) m_excObserver->onException( exception, MessageInfo( msg ) );
	}
	catch ( ... )
	{
		if ( m_excObserver ) m_excObserver->onException( std::logic_error( "Unknown dropped error" ), MessageInfo( msg ) );		
	}
}

} 

}